package com.goa.config;

import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

/**
 * 信号量事务管理器:相当于锁机制
 * 控制针对同一设备的同一秒发送多条指令的同步性
 * 使用TCP发出消息时上锁，响应收到时才释放锁
 */
@Slf4j
public class SemaphoreManager {

    /**
     * key :设备类别 以设备ip区分
     * value:每个类别的信号量 锁
     * ConcurrentHashMap :线程安全，防止并发
     */
    public static final Map<Channel, Semaphore> semaphoreMap = new ConcurrentHashMap<>();

    /**
     * 单例模式 根据类别获取到信号量
     * @param category
     * @return
     */
    public static Semaphore getSemaphore(Channel category) {
        //此方法是存在就返回当前信号量，不存在就创新一个新的信号量，并且指定并发数量为1
        return semaphoreMap.computeIfAbsent(category, k -> new Semaphore(1));
    }

    /**
     * 加锁时 控制过期时间 防止死锁 一但死锁，永远不出去指令。
     * @param category 设备类别
     * @param timeout 过期时间 可适当15-30秒 时间越短，数据丢失的越少。
     * @param unit 过期时间单位
     * @return
     * @throws InterruptedException
     */
    public static boolean tryAcquireSemaphore(Channel category, long timeout, TimeUnit unit) throws InterruptedException {
        Semaphore semaphore = getSemaphore(category);
        return semaphore.tryAcquire(timeout, unit);
    }

    /**
     * 清除某个类别信号量
     * @param category
     */
    public static void removeSemaphore(Channel category) {
        semaphoreMap.remove(category);
    }


}
